/*******************************************************************/
/* @ All Rights Reserved Copyright (C) 2014 broada,Co.,Ltd.        */
/*                                                                 */
/*  NAME      = frstat_ct_conn.c                                   */
/*  NOTE      =                                                    */
/*  DATE      = 2015/01/19 by guojq                                */
/*******************************************************************/
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <pthread.h>

#include "frcomm.h"
#include "frmem.h"
#include "frlog.h"
#include "frlist.h"
#include "frhash2.h"

#define L7_CONNS_HASH_SIZE   100

typedef struct __l7_conns {
    int     i_l7_proto;
    
    unsigned long ul_conns;
    unsigned long ul_conns_avg[4];
} L7_conns;

typedef struct __ct_conns {
    unsigned long ul_conns;             //连接数
    unsigned long ul_conns_avg[4];      //历次连接数
    
    Frhash_header st_l7_conns;          //模块信息hash
} Frct_conns;

FR_STATIC Frct_conns g_st_ct_conns;
FR_STATIC pthread_rwlock_t g_ct_conns_rwlock;

/*******************************************************************************
*  FUNC     :  释放节点内容
*  ARGS     :  p_node 
*  RTN      :
*  NOTE     :  
*******************************************************************************/
FR_STATIC void __l7_node_free(Frlist_node* p_node)
{
    L7_conns *p_l7_node = NULL;
    
    if (p_node && p_node->data)
    {
        p_l7_node = (L7_conns *)p_node->data;
        frfree(p_l7_node);
    }
}

/*******************************************************************************
*  FUNC     :  增加ct总的连接数
*  ARGS     :  ui_conns     增加的连接数
*  RTN      :
*  NOTE     :  
*******************************************************************************/
void frstat_ct_conns_add(unsigned int ui_conns)
{
    pthread_rwlock_wrlock(&g_ct_conns_rwlock);
    g_st_ct_conns.ul_conns += ui_conns;
    pthread_rwlock_unlock(&g_ct_conns_rwlock);
    
    return;
}


/*******************************************************************************
*  FUNC     :  计算平均连接数
*  ARGS     :  p_node           当前节点
*           :  p_data
*  RTN      :  1   (成功)
*  NOTE     :
*******************************************************************************/
FR_STATIC int __frl7_conns_count(Frlist_node* p_node, const void *p_data)
{
    L7_conns *p_st_l7_conns = NULL;

    p_st_l7_conns = (L7_conns *)p_node->data;

    memmove(p_st_l7_conns->ul_conns_avg + 1, p_st_l7_conns->ul_conns_avg, sizeof(unsigned long)*3);

    p_st_l7_conns->ul_conns_avg[0] = p_st_l7_conns->ul_conns;

    return 1;
}

/*******************************************************************************
*  FUNC     :  计算平均连接数
*  ARGS     :
*  RTN      :
*  NOTE     :
*******************************************************************************/
void frstat_ct_l7_conns_count(void)
{
    pthread_rwlock_wrlock(&g_ct_conns_rwlock);
    memmove(g_st_ct_conns.ul_conns_avg + 1, g_st_ct_conns.ul_conns_avg, sizeof(unsigned long)*3);

    g_st_ct_conns.ul_conns_avg[0] = g_st_ct_conns.ul_conns;

    frhash2_run(&g_st_ct_conns.st_l7_conns, NULL, __frl7_conns_count);

    pthread_rwlock_unlock(&g_ct_conns_rwlock);

    return;
}

/*******************************************************************************
*  FUNC     :  增加l7的连接数
*  ARGS     :  i_l7_proto       l7协议名
*           :  ui_conns         增加的连接数
*  RTN      :  FR_SUCC   (成功)
*              FR_FAIL   (失败)
*  NOTE     :  
*******************************************************************************/
int frstat_ct_l7_conns_add(int i_l7_proto, unsigned int ui_conns)
{
    Frlist_node *p_st_node = NULL;
    Frlist_node *p_st_new_node = NULL;
    L7_conns *p_new_l7_conns = NULL;
    
    pthread_rwlock_wrlock(&g_ct_conns_rwlock);
    p_st_node = frhash2_getLong(&g_st_ct_conns.st_l7_conns, i_l7_proto);
    if (p_st_node)
    {
        L7_conns *p_l7_conns = (L7_conns *)p_st_node->data;
        p_l7_conns->ul_conns += ui_conns;
        pthread_rwlock_unlock(&g_ct_conns_rwlock);
        return FR_SUCC;
    }
    
    p_new_l7_conns = (L7_conns *) frmalloc(sizeof(L7_conns));
    if (p_new_l7_conns == NULL)
    {
        pthread_rwlock_unlock(&g_ct_conns_rwlock);
        return FR_FAIL;
    }
    
    memset(p_new_l7_conns, 0x00, sizeof(L7_conns));
    
    p_new_l7_conns->i_l7_proto = i_l7_proto;
    p_new_l7_conns->ul_conns = ui_conns;
    
    p_st_new_node = frlist_node_create(p_new_l7_conns);
    if (p_st_new_node == NULL)
    {
        frfree(p_new_l7_conns);
        pthread_rwlock_unlock(&g_ct_conns_rwlock);
        return FR_FAIL;
    }

    frhash2_addLong(&g_st_ct_conns.st_l7_conns, i_l7_proto, p_st_new_node);
    pthread_rwlock_unlock(&g_ct_conns_rwlock);
    
    return FR_SUCC;
}

/*******************************************************************************
*  FUNC     :  删除其中的一条l7连接
*  ARGS     :  i_l7_proto       l7协议名
*  RTN      :  
*  NOTE     :  
*******************************************************************************/
void frstat_ct_l7_conns_del(int i_l7_proto)
{
    pthread_rwlock_wrlock(&g_ct_conns_rwlock);
    frhash2_delLong(&g_st_ct_conns.st_l7_conns, i_l7_proto, __l7_node_free);
    pthread_rwlock_unlock(&g_ct_conns_rwlock);
    
    return;
}

/*******************************************************************************
*  FUNC     :  初始化ct连接数统计
*  ARGS     :  
*  RTN      :  FR_SUCC   (成功)
*              FR_FAIL   (失败)
*  NOTE     :  
*******************************************************************************/
int frstat_ct_conns_init(void)
{
    if (pthread_rwlock_init(&g_ct_conns_rwlock, NULL) != 0)
    {
        FRLOG_ERROR_DETAIL("pthread_rwlock_init failed");
        return FR_FAIL;
    }
    
    if (frhash2_create(&g_st_ct_conns.st_l7_conns, L7_CONNS_HASH_SIZE) != FR_SUCC)
    {
        FRLOG_ERROR_DETAIL("frhash2_create failed");
        pthread_rwlock_destroy(&g_ct_conns_rwlock);
        return FR_FAIL;
    }
    
    return FR_SUCC;
}

/*******************************************************************************
*  FUNC     :  退出ct连接数统计
*  ARGS     :  
*  RTN      :  
*  NOTE     :  
*******************************************************************************/
void frstat_ct_conns_destroy(void)
{
    pthread_rwlock_wrlock(&g_ct_conns_rwlock);
    frhash2_free(&g_st_ct_conns.st_l7_conns, __l7_node_free);
    pthread_rwlock_unlock(&g_ct_conns_rwlock);
    
    pthread_rwlock_destroy(&g_ct_conns_rwlock);
}
